﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PayloadTracker.APRS.Parsers
{
    class GPGSV : IParser
    {
        /*
         * GPS Satellites in view 

            eg. $GPGSV,3,1,11,03,03,111,00,04,15,270,00,06,01,010,00,13,06,292,00*74
                $GPGSV,3,2,11,14,25,170,00,16,57,208,39,18,67,296,40,19,40,246,00*74
                $GPGSV,3,3,11,22,42,067,42,24,14,311,43,27,05,244,00,,,,*4D

                $GPGSV,1,1,13,02,02,213,,03,-3,000,,11,00,121,,14,13,172,05*67

            1    = Total number of messages of this type in this cycle
            2    = Message number
            3    = Total number of SVs in view
            4    = SV PRN number
            5    = Elevation in degrees, 90 maximum
            6    = Azimuth, degrees from true north, 000 to 359
            7    = SNR, 00-99 dB (null when not tracking)
            8-11 = Information about second SV, same as field 4-7
            12-15= Information about third SV, same as field 4-7
            16-19= Information about fourth SV, same as field 4-7

        */
        enum GPGSVParts : int
        {
            SENTENCEIDENTIFIER = 0,
            NUMSATS = 1,
            MESSAGE = 2,
            NUMMESSAGES = 3,
            SV1PRN = 4,
            SV1ELEV = 5,
            SV1AZIMUTH = 6,
            SV1SNR = 7,
            SV2PRN = 8,
            SV2ELEV = 9,
            SV2AZIMUTH = 10,
            SV2SNR = 11,
            SV3PRN = 12,
            SV3ELEV = 13,
            SV3AZIMUTH = 14,
            SV3SNR = 15,
            SV4PRN = 16,
            SV4ELEV = 17,
            SV4AZIMUTH = 18,
            SV4SNR = 19,
        }

        Dictionary<string, int[]> svs;

        public override APRSBeacon Parse(string sentence)
        {
            //throw new NotImplementedException();
            return null;
        }

        public Dictionary<string, int[]> ParseSV(string sentence)
        {
            string PseudoRandomCode = "";
            int Azimuth = 0;
            int Elevation = 0;
            int SignalToNoiseRatio = 0;
            // Divide the sentence into words
            var Words = Tools.NMEAWords(sentence);
            
            if (Words[((int)GPGSVParts.MESSAGE)] == "1")
            {
                //first message of a message block. Clear old SVs
                int count = Convert.ToInt32(Words[((int)GPGSVParts.NUMMESSAGES)]);
                svs = new Dictionary<string, int[]> { };
            }

            // Each sentence contains four blocks of satellite information.
            // Read each block and report each satellite's information
            int Count = 0;
            for (Count = 1; Count <= 4; Count++)
            {
                // Does the sentence have enough words to analyze?
                if ((Words.Length - 1) >= (Count * 4 + 3))
                {
                    // Yes.  Proceed with analyzing the block.
                    // Does it contain any information?
                    if (Words[Count * 4] != "" && Words[Count * 4 + 1] != "" && Words[Count * 4 + 2] != "" && Words[Count * 4 + 3] != "")
                    {
                        // Yes. Extract satellite information and report it
                        PseudoRandomCode = Words[Count * 4];
                        Elevation = Convert.ToInt32(Words[Count * 4 + 1]);
                        Azimuth = Convert.ToInt32(Words[Count * 4 + 2]);
                        SignalToNoiseRatio = Convert.ToInt32(Words[Count * 4 + 3]);
                        AddSV(PseudoRandomCode, Azimuth,Elevation, SignalToNoiseRatio);
                    }
                }
            }
            if (Words[((int)GPGSVParts.MESSAGE)] == Words[((int)GPGSVParts.NUMMESSAGES)])
            {
                //Last of message block. update satellites.
                //TODO: raise event?
                return svs;
            }
            else
            {
               return null;
            }
        }

        private void AddSV(string PRC, int Azimuth, int Elev, int SNR)
        {
            var data = new int[] { Azimuth, Elev, SNR };
            if(svs.ContainsKey(PRC))
            {
                //update key
                svs[PRC] = data;
            }
            else
            {   
                //add key
                svs.Add(PRC, data);
            }
        }

        public override bool IsValidSentence(string sentence)
        {
            if (!sentence.StartsWith("$GPGSV"))
                return false;

            //Checksum
            int crc = Convert.ToByte(sentence[1]);
            for (int i = 2; i < sentence.Length - 3; i++)
                crc ^= Convert.ToByte(sentence[i]);

            return sentence.EndsWith("*" + crc.ToString("X2"));

        }
    }
}
